package com.hundsun.cprs.yyt.service.match.core.queue;

import com.hundsun.cprs.yyt.service.match.core.queue.visitor.QueueSequenceVisitor;
import com.hundsun.cprs.yyt.service.match.core.queue.visitor.QueueVisitor;
import com.hundsun.cprs.yyt.service.match.domain.TradeEntrust;

/**
 * 以价格为节点的队列，结构是以价格(到分)为单位有序排列的一个链表，每个价格节点中，按照时间升序排列着用户下的订单
 * 
 * @author fish
 * 
 */
public abstract class PriceQueue {

	protected PriceCell leader = getInitLeaderCell();
	/**
	 * 前面价格是否比后面价格更优惠(队列中次序更靠前)
	 */
	protected abstract boolean isPriceFavorable(long price, long compare);

	protected abstract PriceCell getInitLeaderCell();

	/**
	 * 下单
	 */
	public void placeEntrust(TradeEntrust entrust) {
		placeEntrust(this.leader, entrust);
	}

	private PriceCell placeEntrust(PriceCell cell, TradeEntrust entrust) {
		if (cell.getPrice() == entrust.getEntrustPrice()) {// 有对应的价格
			cell.addEntrust(entrust);
			return cell;
		}
		PriceCell next = cell.getNext();
		if (next == null) {
			return insertNewCell(cell, null, entrust);
		}
		// 检查下个价格单元
		if (isPriceFavorable(next.getPrice(), entrust.getEntrustPrice())) {
			return placeEntrust(next, entrust);
		} else {// 麻烦的来了，要插入到当前cell和下个cell之间
			return insertNewCell(cell, next, entrust);
		}
	}

	private PriceCell insertNewCell(PriceCell cell, PriceCell next,
			TradeEntrust entrust) {
		PriceCell create = createNewCell(entrust);
		cell.getWriteLock().lock();
		if (cell.getNext() == next) {
			create.setNext(next);
			cell.setNext(create);
			cell.getWriteLock().unlock();
			return create;
		} else {// 有并发冲突，天啊
			cell.getWriteLock().unlock();
			next = cell.getNext();
			if (isPriceFavorable(next.getPrice(), create.getPrice())) {
				return placeEntrust(next, entrust);
			} else {
				return insertNewCell(cell, next, entrust);
			}
		}
	}

	private PriceCell createNewCell(TradeEntrust entrust) {
		PriceCell cell = new PriceCell(entrust.getEntrustPrice());
		cell.addEntrust(entrust);
		return cell;
	}

	/**
	 * 清理没有订单的cell
	 */
	public void cleanEmptyCell() {
		purge(this.leader);
	}

	/**
	 * 丢弃当前所有节点，重新构造队列
	 */
	public void clean() {
		this.leader = getInitLeaderCell();
	}

	private void purge(PriceCell cell) {
		if (cell == null) {
			return;
		}
		PriceCell next = cell.getNext();
		if (next == null) {
			return;
		}
		if (next.getEntrustSum() != 0) {
			purge(next);
			return;
		}
		cell.getWriteLock().lock();
		if (next.getEntrustSum() != 0) {
			cell.getWriteLock().unlock();
			purge(next);
		} else {
			cell.setNext(next.getNext());
			cell.getWriteLock().unlock();
			purge(cell);
		}
	}

	private boolean remvoeCell(PriceCell cell) {
		if (cell == null) {
			return false;
		}
		PriceCell check = leader;
		PriceCell next = null;
		while ((next = check.getNext()) != null) {
			if (next == cell) {
				check.getWriteLock().lock();
				try {
					PriceCell newNext = next.getNext();
					check.setNext(newNext);
					next.setNext(null);
				} finally {
					check.getWriteLock().unlock();
				}
				return true;
			}
			check = next;
		}
		return false;
	}

	/**
	 * 得到队列头部的单元(价格最优，买队列是价格最高，卖队列是价格最底)
	 * 
	 * @return
	 */
	public PriceCell getHeader() {
		return leader.getNext();
	}

	/**
	 * 从头开始访问队列，
	 * 
	 * @param visitor
	 */
	public void visit(QueueVisitor visitor) {
		PriceCell leader = getHeader();
		if (leader != null) {
			leader.accept(visitor);
		}
	}

	/**
	 * 得到价格队列长度 不进行同步，结果为近似值
	 * 
	 * @return
	 */
	public int getQueueSize() {
		QueueSizeVisitor visitor = new QueueSizeVisitor();
		this.visit(visitor);
		return visitor.size;
	}

	private static class QueueSizeVisitor extends QueueSequenceVisitor {
		int size = 0;

		@Override
		public boolean innerVisit(PriceCell cell) {
			size++;
			return true;
		}
	}

	/**
	 * 得到队列上订单的总数
	 * 
	 * @return
	 */
	public int getQueueEntrustSize() {
		EntrustSizeVisitor visitor = new EntrustSizeVisitor();
		this.visit(visitor);
		return visitor.size;
	}

	private static class EntrustSizeVisitor extends QueueSequenceVisitor {
		int size = 0;

		@Override
		public boolean innerVisit(PriceCell cell) {
			size += cell.getEntrustSum();
			return true;
		}
	}

	/**
	 * 得到这个价格单元中最早的订单
	 * 
	 * @return
	 */
	public TradeEntrust getOldestEntrust() {
		PriceCell pc = this.getHeader();
		if (pc == null) {
			return null;
		}
		return pc.getEntrustQueue().getHeader();
	}

	/**
	 * 删除订单
	 * 
	 * @param entrust
	 * @return
	 */
	public boolean removeEntrust(TradeEntrust entrust) {
		PriceCell cell = this.getHeader();
		while (cell != null) {
			if (cell.removeEntrust(entrust)) {
				// 订单就在这个价格cell里面,删了之后如果这个cell空了,则删掉
				if (cell.isEntrustEmpty()) {
					remvoeCell(cell);
				}
				return true;
			} else {
				cell = cell.getNext();
			}
		}
		return false;
	}

	/**
	 * 根据价格和id删除entrust
	 * 
	 * @param entrustPrice
	 * @param entrustId
	 * @return 被删除的entrust
	 */
	public TradeEntrust removeEntrustByPriceAndId(Long entrustPrice,Long entrustId) {
		TradeEntrust entrust = getEntrustByPriceAndId(entrustPrice, entrustId);
		if (entrust == null) {
			return null;
		}
		this.removeEntrust(entrust);
		return entrust;
	}
	
	/**
	 * 根据价格和委托号删除entrust
	 * 
	 * @param entrustPrice
	 * @param entrustId
	 * @return 被删除的entrust
	 */
	public TradeEntrust removeEntrustByPriceAndEntrustNo(Long entrustPrice,Long entrustId) {
		TradeEntrust entrust = getEntrustByPriceAndEntrustNo(entrustPrice, entrustId);
		if (entrust == null) {
			return null;
		}
		this.removeEntrust(entrust);
		return entrust;
	}

	/**
	 * 根据价格和id找到entrust
	 * 
	 * @param entrustPrice
	 * @param id
	 * @return
	 */
	public TradeEntrust getEntrustByPriceAndId(Long entrustPrice,Long entrustId) {
		if (entrustPrice == null) {
			throw new NullPointerException("entrust price can't be null.");
		}
		if (entrustId == null) {
			throw new NullPointerException("entrust id can't be null.");
		}
		EntrustPriceIdSearcher searcher = new EntrustPriceIdSearcher(
				entrustPrice, entrustId);
		this.visit(searcher);
		return searcher.find;
	}
	
	/**
	 * 根据价格和id找到entrust
	 * 
	 * @param entrustPrice
	 * @param id
	 * @return
	 */
	public TradeEntrust getEntrustByPriceAndEntrustNo(Long entrustPrice,
			Long entrustNo) {
		if (entrustPrice == null) {
			throw new NullPointerException("entrust price can't be null.");
		}
		if (entrustNo == null) {
			throw new NullPointerException("entrust No can't be null.");
		}
		EntrustPriceNoSearcher searcher = new EntrustPriceNoSearcher(entrustPrice, entrustNo);
		this.visit(searcher);
		return searcher.find;
	}

	private static class EntrustPriceIdSearcher extends QueueSequenceVisitor {

		private Long entrustPrice;
		private Long entrustId;
		private TradeEntrust find;

		public EntrustPriceIdSearcher(Long entrustPrice, Long entrustId) {
			super();
			this.entrustId = entrustId;
			this.entrustPrice = entrustPrice;
		}

		@Override
		public boolean innerVisit(PriceCell cell) {
		    if (this.find != null) {
                return false;
            }
			if (cell.getPrice() == entrustPrice) {
				EntrustQueue queue = cell.getEntrustQueue();
				TradeEntrust en = queue.findEntrustById(entrustId);
				if (en != null) {
					this.find = en;
					return false;
				}
			}
			return true;
		}
	}
	
	private static class EntrustPriceNoSearcher extends QueueSequenceVisitor {

		private Long entrustPrice;
		private Long entrustNo;
		private TradeEntrust find;

		public EntrustPriceNoSearcher(Long entrustPrice, Long entrustNo) {
			super();
			this.entrustNo = entrustNo;
			this.entrustPrice = entrustPrice;
		}

		@Override
		public boolean innerVisit(PriceCell cell) {
			if (cell.getPrice() == entrustPrice) {
				EntrustQueue queue = cell.getEntrustQueue();
				TradeEntrust en = queue.findEntrustByEntrustNo(entrustNo);
				if (en != null) {
					this.find = en;
					return false;
				}
			}
			return true;
		}
	}

	/**
	 * 得到此队列上优于此价格的所有订单未成交的数量
	 * 
	 * @return
	 */
	public long getSurplusEntrustAmount(Long price) {
		if (price == null) {
			throw new NullPointerException("price can't be null.");
		}
		EntrustPriceSurplusEntrustAmountSearcher searcher = new EntrustPriceSurplusEntrustAmountSearcher(
				price);
		this.visit(searcher);
		return searcher.amount;
	}

	private class EntrustPriceSurplusEntrustAmountSearcher extends
			QueueSequenceVisitor {
		private long price;
		private long amount = 0;

		public EntrustPriceSurplusEntrustAmountSearcher(long price) {
			super();
			this.price = price;
		}

		@Override
		public boolean innerVisit(PriceCell cell) {
			if (isPriceFavorable(cell.getPrice(), price)) {
				amount += cell.getSurplusEntrustAmount();
				return true;
			}
			return false;
		}
	}

}
